/*
  1. new Promise((resolve, reject) => {}), 执行器立即执行, 调用resolve函数，并传入成功的值，状态变为fulfilled，调用reject并传入失败原因，状态变为rejected
  2. promise有3种状态，fulfilled, rejected, pedding, 并且状态一旦确定，就不可更改了
  3. then方法，有两个回调参数
    3.1 回调如果不是函数，忽略
    3.2 
        成功回调fulfilledCb，参数为fulfilled状态保存的值
        失败回调rejectedCb，参数为rejected状态保存的失败原因

  4. then方法返回一个新promise，可以链式调用。
    4.1 上一个then的成功回调fulfilledCb返回的值，会作为本次then成功回调fulfilledCb的参数
    4.2 then的回调函数不能返回then返回的promise

  5. 一个promise对象可以有多个then，也就是可以注册多个成功或失败回调

  6. then方法，参数可选，并把promise的值传递下去
  6. 错误处理
 */


const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
const PENDING = 'pending';

class FakePromise {
  // 状态值
  state = PENDING

  // 成功的值和失败原因
  value = null
  reason = null

  // 成功和失败回调队列
  fulfilledCbArr = []
  rejectedCbArr = []

  // all方法
  static all(promiseArr) {
    const len = promiseArr.length
    let key = 0
    const result = []

    return new FakePromise((resolve, reject) => {
      promiseArr.forEach((item, i) => {
        // 如果item 是promise，调用then。是普通值，返回普通值
        if (item instanceof FakePromise) {

          item.then(value => {
            result[i] = value

            key = key + 1

            if (key === len) return resolve(result)
          }, reason => {
            return reject(reason)
          })
        } else {
          result[i] = item
        }

      })
    })
  }

  // race方法
  static race(promiseArr) {
    let finish = false

    return new FakePromise((resolve, reject) => {

      promiseArr.forEach((item, i) => {

        if (finish) return

        if (item instanceof FakePromise) {
          item.then(value => {
            finish = true
            resolve(value)
          }, reason => {
            return reject(reason)
          })

        } else {
          finish = true
          resolve(item)
        }

      })
    })
  }

  /* resolve方法
    1. 如果是promise，直接返回
    2. 如果不是promise但有then方法，调用then并将结果，传入resolve或reject
    3. 如果是普通值，新建一个promise并返回
   */
  static resolve(x) {
    if (x instanceof FakePromise) {
      return x
    } else if (typeof x === 'object' || typeof x === 'function' && typeof x.then === 'function') {
      return new FakePromise((resolve, reject) => {
        try {
          x.then(resolve, reject)
        } catch (error) {
          reject(error)
        }
      })
    } else {
      return new FakePromise((resolve, reject) => {
        resolve(x)
      })
    }
  }

  // reject方法
  static resolve(x) {
    return new FakePromise((resolve, reject) => {
      reject(x)
    })
  }

  constructor(excutor) {
    // 执行器立即执行，并传入
    try {
      excutor(this.resolve, this.reject)
    } catch (error) {
      this.reject(error)
    }
  }

  resolve = (value) => {
    // 判断状态，如果状态已经确定了，返回
    if (this.state !== PENDING) return

    // 保存值
    this.value = value
    this.state = FULFILLED

    try {
      // 成功回调存在的话，调用成功回调
      while (this.fulfilledCbArr.length > 0) {
        this.fulfilledCbArr.shift()()
      }

    } catch (error) {
      this.reject(error)
    }
  }

  reject = (reason) => {
    // 判断状态，如果状态已经确定了，返回
    if (this.state !== PENDING) return

    // 保存值
    this.reason = reason
    this.state = REJECTED

    try {
      // 失败回调存在的话，调用失败回调
      while (this.rejectedCbArr.length > 0) {
        this.rejectedCbArr.shift()()
      }

    } catch (error) {
      this.reject(error)
    }
  }

  then(fulfilledCb, rejectedCb) {
    // fulfilledCb, rejectedCb如果不存在，设定默认值
    // fulfilledCb, rejectedCb如果不是函数，忽略
    if (typeof fulfilledCb !== 'function') fulfilledCb = value => value
    if (typeof rejectedCb !== 'function') rejectedCb = reason => { throw reason }

    // 返回新的promise
    const promise2 = new Promise((resolve, reject) => {
      // fulfilledCb和rejected要异步调用
      setTimeout(() => {
        try {
          // 成功状态调用fulfilledCb, 失败状态调用rejectedCb，并传入成功后的值和失败的原因
          if (this.state === FULFILLED) {
            const x = fulfilledCb(this.value)


            resolvePromise(x, resolve, reject, promise2)
          }

          if (this.state === REJECTED) {
            const x = rejectedCb(this.reason)
            resolvePromise(x, resolve, reject, promise2)
          }

          if (this.state === PENDING) {
            // 如果是pending，存储回调（使用函数包装处理，使resoresolvePromise延时调用）
            this.fulfilledCbArr.push(() => resolvePromise(fulfilledCb(this.value), resolve, reject, promise2))

            this.rejectedCbArr.push(() => resolvePromise(rejectedCb(this.reason), resolve, reject, promise2))
          }
        } catch (error) {
          reject(error)
        }
      }, 0)
    })

    return promise2
  }


  /* catch
    then语法糖，相对于不传成功回调
   */
  catch (failCb) {
    return this.then(undefined, failCb)
  }

  /* finally
    then语法糖，在成功和失败中分别调用finally回调
   */
  finally (cb) {
    return this.then(value => {
      return FakePromise.resolve(cb()).then(() => value)
    }, reason => {
      return FakePromise.resolve(cb()).then(() => {throw reason})
    })
  }
}

/* 1. 如果x === promise, 调用reject返回TypeError
  2. 如果x是promise，调用then，判断promise的状态，成功调用resolve，失败调用reject，并床单x的返回值
  3. 如果x是一个函数或对象
    3.1 调用x的then方法，如果报错，调用reject,并返回错误
    3.2 如果x的then是一个函数，将x作为this调用then,并传入resolve和reject
  4. 如果x是普通值，调用resolve
 */

function resolvePromise(x, resolve, reject, promise2) {
  if (x === promise2) return reject(new TypeError('chaining cycle detected for promise'))

  if (x instanceof FakePromise) {
    x.then(resolve, reject)
  } else if (typeof x === 'function' || typeof x === 'object') {
    try {
      x.then.call(x, resolve, reject)
    } catch (error) {
      reject(error)
    }
  } else {
    resolve(x)
  }
}

module.exports = FakePromise